package testtiles.object;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

import butines.core.math2d.Vector2D;
import butines.core.math2d.Vector2DUtils;
import butines.game.Messenger;

public class UnitGroup {

	private ArrayList<Unit> units = new ArrayList<Unit>();

	public ArrayList<Unit> getUnits() {
		return units;
	}

	public void add(Unit unit) {
		if (units.contains(unit) == false) {
			units.add(unit);
		}
	}

	public void remove(Unit unit) {
		units.add(unit);
	}

	public void move(Messenger messenger, Vector2D targetPoint) {
		int len = units.size();
		
		float radius = 0;
		int i = 0;
		Pos[] arr = new Pos[len];
		for (Unit unit: units) {
			float dist = Vector2DUtils.distance(unit.getPosition(), targetPoint);
			arr[i++] = new Pos(unit, dist);
			radius += unit.getViewDistance();
		}
		radius /= len;
		Arrays.sort(arr);

		Formation formation = new Formation();
		formation.square(targetPoint, len, radius);
		
		for (i = 0; i < len; i++) {
			Vector2D target = formation.getNearTargetPoint(arr[i].unit);
			messenger.dispatch(Messages.MOVE, null, arr[i].unit, 0, target.x, target.y);
		}
		
//		Unit leader = arr[0].unit;
//		for (i = len - 1; i > 0; i--) {
//			Vector2D offset = formation.getNearTargetPoint(arr[i].unit);
//			messenger.dispatch(Messages.FOLLOW_LEADER, leader, arr[i].unit, 0, offset);
//		}
//		
//		Vector2D offset = formation.getNearTargetPoint(leader);
//		targetPoint.add(offset);
//		messenger.dispatch(Messages.MOVE, null, leader, 0, targetPoint.x, targetPoint.y);
		
	}
	
	private class Pos implements Comparable<Pos> {
		float distance;
		Unit unit;
		
		public Pos(Unit unit, float distance) {
			this.unit = unit;
			this.distance = distance;
		}

		public int compareTo(Pos other) {
			float value = (this.distance - other.distance);
			return value > 0 ? 1 : (value < 0 ? -1 : 0);
		}

	}
		
	private class Formation {
	
		private Vector2D[] targets;
		private LinkedList<Vector2D> available;
		
		public Formation() {
			
		}
		
		public void square(Vector2D targetPoint, int numUnits, float radius) {
			
			int len = (int)Math.ceil(Math.sqrt(numUnits));
			int size = len*len;
			float padding = radius * 2;
			
			float dx = 0;
			float dy = 0;
			Vector2D center = new Vector2D();
			
			targets = new Vector2D[size];
			for (int i = 0; i < size; ) {
				targets[i] = new Vector2D(dx, dy);
				center.add(targets[i]);
				i++;
				dx += padding;
				if (i % len == 0) {
					dx = 0;
					dy += padding;
				}
			}
			center.div(size);
			
			available = new LinkedList<Vector2D>();
			for (int i = 0; i < size; i++) {
				targets[i].sub(center);
				targets[i].add(targetPoint);
				available.add(targets[i]);
			}
		}

		public Vector2D getNearTargetPoint(Unit unit) {
			Vector2D targetPoint = null;
			float minDist = Float.MAX_VALUE;
			for (Vector2D target: available) {
				float dist = Vector2DUtils.distance(unit.getPosition(), target);
				if (minDist > dist) {
					minDist = dist;
					targetPoint = target;
				}
			}
			available.remove(targetPoint);
			return targetPoint;
		}
		
	}


}
